/**
  ******************************************************************************
  * @file    driver_esp8266.c
  * @brief   ESP8266 MQTT 通信驱动层（适用于 OneNET 平台）
  * @author  Baoxi
  * @version 2.0
  * @date    2025-10-22
  ******************************************************************************
  */

#include "driver_esp8266.h"
#include "cJSON.h"
#include "usart.h"
#include "light.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/*==============================================================================
 *                               WiFi 配置区
 *============================================================================*/
#define WIFI_SSID               "DL"
#define WIFI_PASSWORD           "12345678"
#define ONENET_MQTT_PRODUCT_ID  "zCfbgok2W9"
#define ONENET_MQTT_DEVICE_NAME "test"
#define ONENET_MQTT_TOKEN       "version=2018-10-31&res=products%2FzCfbgok2W9%2Fdevices%2Ftest&et=2053320694&method=md5&sign=I1rVI1cdvtJk79xIgjzNzg%3D%3D"

/*==============================================================================
 *                              OneNET AT指令区
 *============================================================================*/
#define WIFI_JOIN_AP_CMD        "AT+CWJAP=\"" WIFI_SSID "\",\"" WIFI_PASSWORD "\"\r\n"
#define MQTT_SERVER_CMD         "AT+MQTTCONN=0,\"mqtts.heclouds.com\",1883,1\r\n"
#define MQTT_USERCFG_CMD        "AT+MQTTUSERCFG=0,1,\"" ONENET_MQTT_DEVICE_NAME "\",\"" ONENET_MQTT_PRODUCT_ID "\",\"" ONENET_MQTT_TOKEN "\",0,0,\"\"\r\n"
#define MQTT_PUBTOPIC_CMD       "AT+MQTTPUB=0,\"$sys/" ONENET_MQTT_PRODUCT_ID "/" ONENET_MQTT_DEVICE_NAME "/thing/property/post\""
#define MQTT_SUBTOPIC_CMD       "AT+MQTTSUB=0,\"$sys/" ONENET_MQTT_PRODUCT_ID "/" ONENET_MQTT_DEVICE_NAME "/thing/property/set\",0\r\n"
#define MQTT_PUBSET_CMD         "AT+MQTTPUB=0,\"$sys/" ONENET_MQTT_PRODUCT_ID "/" ONENET_MQTT_DEVICE_NAME "/thing/property/set_reply\""

/*==============================================================================
 *                             全局对象与变量区
 *============================================================================*/
Wireless_TypeDef WirelessStatus = {0};

OneNET_CMD lamp_level = {"LM", 0};
OneNET_CMD lamp_mode  = {"Md", 0};
OneNET_CMD lamp_person= {"Se", 0};
OneNET_CMD lamp_thr   = {"val", 80};

/* 外部信号量 */
extern osSemaphoreId_t WiFi_txSemaphore;
extern osSemaphoreId_t WiFi_rxSemaphore;

/* 内部函数声明 */
static uint8_t wireless_send_command(const char *cmd, const char *res, uint8_t retry, uint8_t printf_enable);
static char*   wireless_find_json(char *cmd);
static uint32_t wireless_parse_command_id(char *jsonData);
static void    wireless_extract_command(char *jsonData);
static void    wireless_send_response(uint32_t respond_id, uint16_t code, const char *msg);

/* 通用宏映射 */
#define wireless_delay_ms(ms)  osDelay(ms)
#define wireless_send_data     WiFi_DMA_Data
#define wireless_printf        log_printf

/*==============================================================================
 *                             基础通信函数实现
 *============================================================================*/

/**
  * @brief  发送 AT 指令并匹配响应
  * @param  cmd: AT指令字符串
  * @param  res: 期望响应关键字
  * @param  retry: 最大重试次数
  * @param  printf_enable: 是否打印通信内容
  * @retval 0 成功 / 1 失败
  */
static uint8_t wireless_send_command(const char *cmd, const char *res, uint8_t retry, uint8_t printf_enable)
{
    uint8_t rxBuf[WIFI_RX_BUFFER_SIZE] = {0};
    uint8_t status = 1;

    for (uint8_t i = 0; i < retry; i++)
    {
        if (printf_enable) wireless_printf(">> %s", cmd);
        wireless_send_data(cmd);

        uint16_t len = WiFi_GetReceivedData(rxBuf);
        if (len > 0 && strstr((const char *)rxBuf, res))
        {
            if (printf_enable) wireless_printf("<< %s\r\n", rxBuf);
            status = 0;
            break;
        }

        wireless_printf("[AT] Retry %d failed.\r\n", i + 1);
        wireless_delay_ms(300);
    }
    return status;
}

/*==============================================================================
 *                            初始化与连接管理
 *============================================================================*/

/**
  * @brief  ESP8266 模块初始化
  * @note   自动执行连接 WiFi 与 OneNET 平台
  */
void Wireless_Init(void)
{
    wireless_printf("\r\n[WiFi] Starting ESP8266 MQTT Service...\r\n");

    typedef struct {
        const char *cmd;
        const char *res;
        uint16_t errBit;
        uint16_t delayMs;
    } CmdTable;

    const CmdTable initCmds[] = {
        {"AT+RST\r\n", "",              1 << 0, 500},
        {"ATE0\r\n", "OK",              1 << 1, 100},
        {"AT+CWAUTOCONN=0\r\n", "OK",   1 << 2, 100},
        {"AT+CWMODE=1\r\n", "OK",       1 << 3, 100},
        {"AT+CWDHCP=1,0\r\n", "OK",     1 << 4, 100},
        {WIFI_JOIN_AP_CMD, "GOT IP",    1 << 5, 500},
        {MQTT_USERCFG_CMD, "OK",        1 << 6, 100},
        {MQTT_SERVER_CMD,  "OK",        1 << 7, 100},
        {MQTT_SUBTOPIC_CMD,"OK",        1 << 8, 100},
    };

    WirelessStatus.initErrorCode = 0;

    for (uint8_t i = 0; i < ARRAY_SIZE(initCmds); i++)
    {
        if (wireless_send_command(initCmds[i].cmd, initCmds[i].res, MAX_RETRY_COUNT, W_ENABLE))
        {
            WirelessStatus.initErrorCode |= initCmds[i].errBit;
            wireless_printf("[ERR] %s failed.\r\n", initCmds[i].cmd);
        }
        wireless_delay_ms(initCmds[i].delayMs);
    }

    if (WirelessStatus.initErrorCode == 0)
    {
        WirelessStatus.initFlag = 1;
        wireless_printf("[WiFi] MQTT Service Started Successfully.\r\n");
    }
    else
    {
        WirelessStatus.initFlag = 0;
        wireless_printf("[WiFi] Init failed, ErrorCode=0x%04X\r\n", WirelessStatus.initErrorCode);
        wireless_error_handler(WirelessStatus.initErrorCode);
    }
}

/*==============================================================================
 *                             JSON命令解析函数
 *============================================================================*/

/**
  * @brief  获取字符串中的 JSON 起始位置
  */
static char* wireless_find_json(char *cmd)
{
    return strchr(cmd, '{');
}

/**
  * @brief  获取 OneNET 命令 ID
  */
static uint32_t wireless_parse_command_id(char *jsonData)
{
    cJSON *root = cJSON_Parse(jsonData);
    if (!root) return 0xFFFFFFFFU;

    uint32_t id = 0;
    cJSON *item = cJSON_GetObjectItem(root, "id");
    if (cJSON_IsString(item)) id = atoi(item->valuestring);

    cJSON_Delete(root);
    return id;
}

/**
  * @brief  回复 OneNET 平台的命令响应
  */
static void wireless_send_response(uint32_t respond_id, uint16_t code, const char *msg)
{
    char jsonData[256];
    snprintf(jsonData, sizeof(jsonData),
             "%s,\"{\\\"id\\\":\\\"%lu\\\"\\,\\\"code\\\":%u\\,\\\"msg\\\":\\\"%s\\\"}\",0,0\r\n",
             MQTT_PUBSET_CMD, (unsigned long)respond_id, code, msg);

    wireless_send_command(jsonData, "OK", 3, W_DISABLE);
}

/**
  * @brief  解析 OneNET 下发的控制命令
  */
static void wireless_extract_command(char *jsonData)
{
    cJSON *root = cJSON_Parse(jsonData);
    if (!root) return;

    cJSON *params = cJSON_GetObjectItem(root, "params");
    if (!params) { cJSON_Delete(root); return; }

    struct { OneNET_CMD *cmd; const char *name; } items[] = {
        {&lamp_level, lamp_level.name},
        {&lamp_mode,  lamp_mode.name},
        {&lamp_person,lamp_person.name},
        {&lamp_thr,   lamp_thr.name},
    };

    for (uint8_t i = 0; i < ARRAY_SIZE(items); i++)
    {
        cJSON *item = cJSON_GetObjectItem(params, items[i].name);
        if (cJSON_IsNumber(item) || cJSON_IsBool(item))
        {
            items[i].cmd->value = item->valueint;
            wireless_printf("[CMD] %s = %d\r\n", items[i].name, items[i].cmd->value);
        }
    }
    cJSON_Delete(root);
}

/*==============================================================================
 *                             接收与发布接口函数
 *============================================================================*/

/**
  * @brief  MQTT 数据接收处理回调
  * @retval 1 成功处理 / 0 无数据
  */
uint8_t wireless_receive_handler(void)
{
    uint8_t rx[WIFI_RX_BUFFER_SIZE];
    uint16_t len = WiFi_GetReceivedData(rx);
    if (len == 0) return 0;

    rx[(len < WIFI_RX_BUFFER_SIZE) ? len : (WIFI_RX_BUFFER_SIZE - 1)] = '\0';
    if (!strstr((char *)rx, "+MQTTSUBRECV")) return 0;

    char *jsonData = wireless_find_json((char *)rx);
    if (!jsonData) return 0;

    wireless_printf("[RX JSON] %s\r\n", jsonData);
    uint32_t cmd_id = wireless_parse_command_id(jsonData);
    wireless_extract_command(jsonData);
    wireless_send_response(cmd_id, 200, "success");

    return 1;
}

/**
  * @brief  发布多类型属性数据到 MQTT (OneNET)
  * @param  intCount: 整型参数数量
  * @param  intIdf[]: 整型标识符数组
  * @param  intValues[]: 整型值数组
  * @param  floatCount: 浮点参数数量
  * @param  floatIdentifiers[]: 浮点标识符数组
  * @param  floatValues[]: 浮点值数组
  * @param  boolCount: 布尔参数数量
  * @param  boolIdf[]: 布尔标识符数组
  * @param  boolValue[]: 布尔值数组
  * @param  stringCount: 字符串参数数量
  * @param  stringIdentifiers[]: 字符串标识符数组
  * @param  stringValues[]: 字符串值数组
  * @retval 无
  * @note   发送格式: {"id":"123","params":{"key":{"value":xxx},...}}
  */
void wireless_publish_data(uint8_t intCount, const char *intIdf[], uint32_t intValues[],
                           uint8_t floatCount, const char *floatIdentifiers[], float floatValues[],
                           uint8_t boolCount,  const char *boolIdf[], W_bool boolValue[],
                           uint8_t stringCount, const char *stringIdentifiers[], const char *stringValues[])
{
    const uint16_t BUFFER_SIZE = 256;
    char globalBuffer[BUFFER_SIZE];
    size_t pos = 0;
    bool first = true;

    // 开头
    pos += snprintf(globalBuffer + pos, BUFFER_SIZE - pos, "%s,\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{", MQTT_PUBTOPIC_CMD);

    // 整型
    for (uint8_t i = 0; i < intCount; i++) {
        if (!first) pos += snprintf(globalBuffer + pos, BUFFER_SIZE - pos, "\\,");
        pos += snprintf(globalBuffer + pos, BUFFER_SIZE - pos, "\\\"%s\\\":{\\\"value\\\":%lu}", intIdf[i], (unsigned long)intValues[i]);
        first = false;
    }

    // 浮点型
    for (uint8_t i = 0; i < floatCount; i++) {
        if (!first) pos += snprintf(globalBuffer + pos, BUFFER_SIZE - pos, "\\,");
        pos += snprintf(globalBuffer + pos, BUFFER_SIZE - pos, "\\\"%s\\\":{\\\"value\\\":%.2f}", floatIdentifiers[i], (double)floatValues[i]);
        first = false;
    }

    // 布尔型
    for (uint8_t i = 0; i < boolCount; i++) {
        if (!first) pos += snprintf(globalBuffer + pos, BUFFER_SIZE - pos, "\\,");
        pos += snprintf(globalBuffer + pos, BUFFER_SIZE - pos, "\\\"%s\\\":{\\\"value\\\":%s}", boolIdf[i], boolValue[i] ? "true" : "false");
        first = false;
    }

    // 字符串型
    for (uint8_t i = 0; i < stringCount; i++) {
        if (!first) pos += snprintf(globalBuffer + pos, BUFFER_SIZE - pos, "\\,");
        pos += snprintf(globalBuffer + pos, BUFFER_SIZE - pos, "\\\"%s\\\":{\\\"value\\\":\\\"%s\\\"}", stringIdentifiers[i], stringValues[i]);
        first = false;
    }

    // 结尾
    pos += snprintf(globalBuffer + pos, BUFFER_SIZE - pos, "}}\",0,0\r\n");

    if (pos >= BUFFER_SIZE - 1) {
        printf("[ERROR] Payload too long (%zu bytes)\r\n", pos);
        return;
    }

    printf("[DEBUG] MQTT Payload: %s\r\n", globalBuffer);
    wireless_send_data(globalBuffer);
}


/**
  * @brief  无线通信错误回调（用户可重写）
  */
__weak void wireless_error_handler(uint16_t ErrorCode)
{
    (void)ErrorCode;
}
